/**
 * 命令模式：将一个请求封装为一个对象，使发出请求的责任和执行请求的责任分割开。这样两者之间通过命令对象进行沟通，这样方便将命令对象进行储存、传递、调用、增加与管理。
 * 命令模式适合应用场景：
 * 1. 需要通过操作来参数化对象时，可使用命令模式。命令模式可将特定的方法调用转化为独立对象。这一改变也带来了许多有趣的应用：你可以将命令作为方法的参数进行传递、将命令保存在其他对象中，或者在运行时切换已连接的命令等。
 * 2. 想要将操作放入队列中、操作的执行或者远程执行操作，可使用命令模式。同其他对象一样，命令也可以实现序列化（序列化的意思是转化为字符串），从而能方便地写入文件或数据库中 一段时间后，该字符串可被恢复成为最初的命令对象。因此，可以延迟或计划命令的执行。但其功能远不止如此！使用同样的方式，还可以将命令放入队列、记录命令或者通过网络发送命令。
 * 优点：
 * 1. 单一职责原则。可以解耦触发和执行操作的类。
 * 2. 开闭原则。可以在不修改已有客户端代码的情况下在程序中创建新的命令。
 * 3. 可以实现操作的延迟执行。
 * 4. 可以将一组简单命令组合成一个复杂命令。
 */
#pragma once

#include <iostream>
#include <string>
#include <memory>

using namespace std;

namespace command
{

// Command 接口声明了一个执行命令的方法。
class Command {
public:
    virtual ~Command() {}
    virtual void Execute() const = 0;
};

// 有些命令可以实现简单的操作。
class SimpleCommand : public Command {
public:
  explicit SimpleCommand(const string& strCommand) : m_strCmmand(strCommand) {}
  void Execute() const override {
    cout << "SimpleCommand: See, I can do simple things like printing (" << this->m_strCmmand << ")" << endl;
  }

private:
    string m_strCmmand;
};

// Receiver 类包含一些重要的业务逻辑。它们知道如何执行与执行请求相关的各种操作。事实上，任何类都可以作为一个接收者。
class Receiver {
public:
    void DoSomething(const string& a) {
        cout << "Receiver: Working on (" << a << ".)" << endl;
    }
    void DoSomethingElse(const string& b) {
        cout << "Receiver: Also working on (" << b << ".)" << endl;
    }
};

// 但是，某些命令可以将更复杂的操作委派给其他对象.
class ComplexCommand : public Command {
public:
    // 复杂的命令可以通过构造函数接受一个或几个接收器对象以及任何上下文数据。
    ComplexCommand(shared_ptr<Receiver> receiver, const string& a, const string& b) : m_receiver(receiver), m_dataA(a), m_dataB(b) {}
    void Execute() const override {
        cout << "ComplexCommand: Complex stuff should be done by a receiver object." << endl;
        m_receiver->DoSomething(this->m_dataA);
        m_receiver->DoSomethingElse(this->m_dataB);
    }
private:
    shared_ptr<Receiver> m_receiver;
    // 上下文数据，用于启动接收器的方法。
    string m_dataA;
    string m_dataB;
};

// 调用程序与一个或多个命令相关联，它向命令发送请求。
class Invoker {
public:
    void SetOnStart(shared_ptr<Command> command) {
        on_start = command;
    }
    void SetOnFinish(shared_ptr<Command> command) {
        on_finish = command;
    }

    // Invoker 不依赖于具体的命令或接收器类。调用者通过执行命令间接地将请求传递给接收者。
    void DoSomethingImportant() {
        cout << "Invoker: Does anybody want something done before I begin?" << endl;
        if (on_start) {
            on_start->Execute();
        }
        cout << "Invoker: ...doing something really important..." << endl;
        cout << "Invoker: Does anybody want something done after I finish?" << endl;
        if (on_finish) {
            on_finish->Execute();
        }
    }
private:
    shared_ptr<Command> on_start;
    shared_ptr<Command> on_finish;
};

void ClientCode()
{
    unique_ptr<Invoker> invoker(new Invoker);
    invoker->SetOnStart(shared_ptr<SimpleCommand>(new SimpleCommand("Say Hi!")));
    shared_ptr<Receiver> receiver (new Receiver);
    invoker->SetOnFinish(shared_ptr<ComplexCommand>(new ComplexCommand(receiver, "Send email", "Save report")));
    invoker->DoSomethingImportant();
}
} // namespace command